#include <stdio.h>
#include <stdlib.h>

typedef int (*fptrSet)(void*, int);
typedef int (*fptrGet)(void*);
typedef void (*fptrDisplay)(void*);

typedef double (*fptrGetArea)(void*);

////////////////////////////////////////////////////////////
//定义基类Shape
typedef struct _shape {
    //定义基类函数成员
    struct {
        fptrSet setX;
        fptrGet getX;
        fptrSet setY;
        fptrGet getY;
        fptrDisplay display;
    };
    //定义基类数据成员
    int x;
    int y;
} Shape;

//函数成员的实现，独立函数还未绑定
void shapeDisplay(Shape* shape) {
    printf("Shape\n");
}
void shapeSetX(Shape* shape, int x) {
    shape->x = x;
}
void shapeSetY(Shape* shape, int y) {
    shape->y = y;
}
int shapeGetX(Shape* shape) {
    return shape->x;
}
int shapeGetY(Shape* shape) {
    return shape->y;
}
//定义构造函数：数据成员以参数传值，绑定独立的函数（为函数成员赋值）
Shape* shapeConstructor(int x, int y) {
    Shape* shape = (Shape*)malloc(sizeof(Shape));
    shape->x = x;
    shape->y = y;
    shape->display = shapeDisplay;
    shape->setX = shapeSetX;
    shape->setY = shapeSetY;
    shape->getX = shapeGetX;
    shape->getY = shapeGetY;
    return shape;
}
////////////////////////////////////////////////////////////

//定义派生类
////////////////////////////////////////////////////////////
typedef struct _rectangle {
    //维护一个基类成员变量，必须为变量，不能用指针
    Shape base;

    //派生类额外的函数成员
    fptrGetArea func1;

    //派生类额外的数据成员
    int width;
    int height;
} Rectangle;

//覆盖基类的dispalay方法
void rectangleDisplay(Rectangle* rectangle) {
    printf("Rectangle\n");
}

//实现派生类额外的函数成员
double getArea(Rectangle* rectangle) {
    return rectangle->width * rectangle->height;
}

//定义构造函数
Rectangle* rectangleConstructor(int width, int height, int x, int y) {
    Rectangle* rectangle = (Rectangle*)malloc(sizeof(Rectangle));

    //初始化派生类中额外的成员
    rectangle->width = width;
    rectangle->height = height;
    rectangle->func1 = getArea;

    //初始化派生类中的基类变量
    rectangle->base =
        (Shape){.x = x,
                .y = y,
                .display = rectangleDisplay,  //此处指定为新的显示函数
                .setX = shapeSetX,
                .setY = shapeSetY,
                .getX = shapeGetX,
                .getY = shapeGetY};
    return rectangle;
}
////////////////////////////////////////////////////////////

int main() {
    //构造三个对象
    Shape* shapes[3];
    shapes[0] = shapeConstructor(0, 0);
    shapes[1] = rectangleConstructor(100, 200, 50, 50);
    shapes[2] = shapeConstructor(600, 600);

    //输出三个对象
    for (int i = 0; i < 3; i++) {
        shapes[i]->display(shapes[i]);
        printf("%d\n", shapes[i]->getX(shapes[i]));
    }

    //输出shapes[1]中display函数的地址
    printf("%p\n", ((Rectangle*)shapes[1])->base.display);
    printf("%p\n", shapes[1]->display);

    //输出shapes[1]的面积，对于派生类特有的函数，应该转变为派生类指针后再访问
    printf("area=%lf\n", ((Rectangle*)shapes[1])->func1(shapes[1]));

    return 0;
}
